package com.cheng.zenofdesignpatterns.patterns.singleton;

import android.view.View;

import com.cheng.zenofdesignpatterns.ZoDPChapterBaseActivity;

public class ZoDPSingletonActivity extends ZoDPChapterBaseActivity {

    @Override
    protected void initData() {
        mTitleTV.setText("单例模式");
        String content = "定义：\n" +
                "Ensure a class has only one instance, and provide a global point of access " +
                "to it.\n" +
                "确保某一个类只有一个实例，而且自行实例化并向整个系统提供这个实例。\n\n" +
                "单例模式的优点\n" +
                "- 减少了内存开支\n" +
                "- 减少了系统的性能开销\n" +
                "- 可以避免对资源的多重占用\n" +
                "- 可以在系统设置全局的访问点，优化和共享资源访问，例如可以设计一个单例类，负责" +
                "所有数据表的映射处理。\n" +
                "单例模式的缺点\n" +
                "- 一般没有接口，扩展很困难\n" +
                "单例模式为什么不能增加接口呢？因为接口对单例模式是没有任何意义的，它要求‘自行实" +
                "例化’，并且提供单一实例、接口或抽象类是不可能被实例化的。当然，在特殊情况下，单" +
                "例模式可以实现接口、被继承等，需要在系统开发中根据环境判断。\n" +
                "- 对测试是不利的\n" +
                "在并行开发环境中，如果单例模式没有完成，是不能进行测试的，没有接口也不能使用mock" +
                "的方式虚拟一个对象。\n" +
                "- 与单一职责原则有冲突\n" +
                "一个类应该只实现一个逻辑，而不不关心它是否是单例的，是不是单例要取决于环境，单例" +
                "模式把‘要单例’和业务逻辑融合在一个类中。\n\n" +
                "使用场景\n" +
                "在一个系统中，要求一个类有且仅有一个对象，如果出现多个对象就会出现‘不良反应’，可以" +
                "采用单例模式，具体的场景如下：\n" +
                "- 要求生成唯一序列号的环境" +
                "- 在整个项目中需要一个共享访问点或共享数据\n" +
                "例如一个Web页面上的计数器，可以不用把每次刷新都记录到数据库中，使用单例模式保持计" +
                "数器的值，并确保是线程安全的\n" +
                "- 创建一个对象需要消耗的资源过多，如要访问IO和数据库等资源\n" +
                "- 需要定义大量的静态常量和静态方法（如工具类）的环境（当然也可直接声明为static）\n\n" +
                "单例模式的注意事项\n" +
                "- 在高并发情况下，注意单例模式的线程同步问题\n" +
                "- 需要考虑对象的复制情况（不要实现Cloneable接口）\n\n" +
                "最佳实践\n" +
                "在Spring中，每个Bean默认就是单例的，这样做的优点是Spring容器可以管理这些Bean的生命" +
                "期，决定什么时候创建出来，什么时候销毁，销毁的时候要如何处理，等等。如果采用非单例模式" +
                "（Prototype类型），则Bean初始化后的管理交由JEE容器，Spring容器不再跟踪管理Bean的生命周期。";
        mContentTV.setText(content);
    }

    @Override
    public void onClick(View v) {
        // 定义5个大臣
        int ministerNum = 5;
        for (int i = 0; i < ministerNum; i++) {
            Emperor emperor = Emperor.getInstance();
            System.out.println("第" + (i + 1) + "个大臣参拜的是：");
            emperor.say();
        }
    }

    /**
     * 对我来说，我比较喜欢第三种和第五种方式，简单易懂，而且在JVM层实现了线程安全（如果不是多个类加载器环
     * 境），一般的情况下，我会使用第三种方式，只有在要明确实现lazy loading效果时才会使用第五种方式，另外，
     * 如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例，不过，我一直会保证我的程序是线程安全的，
     * 而且我永远不会使用第一种和第二种方式，如果有其他特殊的需求，我可能会使用第七种方式，毕竟，JDK1.5已经
     * 没有双重检查锁定的问题了。
     * ========================================================================
     * 不过一般来说，第一种不算单例，第四种和第三种就是一种，如果算的话，第五种也可以分开写了。所以说，一般
     * 单例都是五种写法。懒汉，恶汉，双重校验锁，枚举和静态内部类
     */
}
